using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;

namespace OpenLS.Spreadsheet.Formats.Biff
{
    class ArrayIntDictionary<TValue> 
    {
        internal ArrayIntDictionary(Func<TValue, bool> nilValuePredicate, TValue nilValue)
        {
            Contract.Assert(nilValuePredicate(nilValue));
            this._nilValuePredicate = nilValuePredicate;
            _nilValue = nilValue;

        }

        private int _count;

        public int Count
        {
            get { return _count; }
        }
        TValue[] _inner = new TValue[0];
        internal readonly Func<TValue, bool> _nilValuePredicate;
        private readonly TValue _nilValue;

        public IEnumerable<TValue> Values
        {
            get { return Enumerable.Where(_inner, t => !_nilValuePredicate (t)); }
        }

        public TValue this[int key]
        {
            get {
                if (key < _inner.Length)
                    return _inner[key];
                return _nilValue;
            }
        }

        public bool TryGetValue(int key, out TValue result)
        {
            if (key < _inner.Length)
            {
                result = _inner[key];
                return !_nilValuePredicate(result );
            }
            result = _nilValue;
            return false;
        }

        public void Add(int key, TValue value)
        {
            Contract.Requires(key >= 0);
            Contract.Assert(!_nilValuePredicate(value));
            Contract.Assert(Enumerable.Count(Values) == Count);
            if (key >= _inner.Length)
            {
                var newInner = new TValue[1 + key*2];
                for (int i = _inner.Length; i < newInner.Length; i++)
                    newInner[i] = _nilValue;
                Array.Copy(_inner, newInner, _inner.Length);
                _inner = newInner;
            }
            if (_nilValuePredicate( _inner[key]))
                _count++;
            else
            {
                
            }
            _inner[key] = value;
#if DEBUG
            int valueCount = Enumerable.Count(Values);
            if (valueCount != Count)
                Contract.Assert(valueCount == Count);
            Contract.Assert(Enumerable.Count(Values) == Count);
#endif
        }
    }
}